package com.husd.framework.ddl_new;

import com.husd.framework.code.DDLIndex;
import com.husd.framework.code.ReferenceDefinition;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 解析索引声明
 *
 * @author shengdonghu@126.com
 * @date 2024/1/23 17:58
 */
public class MySQLTable0202IndexParse {

    private List<List<String>> columnList;

    public MySQLTable0202IndexParse(List<List<String>> columnList) {
        this.columnList = columnList;
    }

    public List<DDLIndex> parse() {

        List<DDLIndex> res = new ArrayList<>();

        for (List<String> sub : columnList) {

            DDLIndex ddlIndex = new DDLIndex();
            WordListScanner wordListScanner = new WordListScanner(sub);
            CreateDefinitionTypeEnum _step = CreateDefinitionTypeEnum.index;
            String next = "";
            String nextnext = "";
            String pre = "";
            String prepre = "";

            // 整体的策略就是发现了某一个关键字 就进入某个表达式的阶段 按这个表达式解析
            // 表达式后面如果是可选的 就直接break 表达式后面是必填的 就直接解析出来
            while (wordListScanner.haveWord()) {
                String current = wordListScanner.current();
                next = wordListScanner.getNextWord();
                nextnext = wordListScanner.getNextNextWord();
                pre = wordListScanner.getPreWord();
                prepre = wordListScanner.getPrePreWord();
                switch (current) {
                    // index and key   same
                    case "index":
                    case "key":
                        ddlIndex.setPre(ddlIndex.getPre() + " " + current);

                        //  {INDEX | KEY}  [index_name] [index_type] (key_part,...) [index_option] ...
                        //1 index_name (
                        //2 using      btree (           | using hash (
                        //3 index_name using btree (
                        //4 (
                        String firstWord = null;

                        String indexName = null;
                        String indexType = null;
                        String _index_expr = null;

                        wordListScanner.next(); // index_name or index_type
                        firstWord = wordListScanner.current();
                        // 要先处理第4种情况
                        if (ParseUtil.isWord(firstWord, "(")) {
                            //4 直接拿到 _index_expr
                            indexName = null;
                            indexType = null;
                            _index_expr = wordListScanner.findMatchDiffPair("(", ")");
                        } else if (ParseUtil.isWord(firstWord, "using")) {
                            //2
                            indexName = null;
                            wordListScanner.next(); // now is btree or hash
                            indexType = wordListScanner.current();
                            wordListScanner.next(); // now is (
                            _index_expr = wordListScanner.findMatchDiffPair("(", ")");
                        } else {
                            // 第1种或者第3种情况
                            indexName = firstWord;
                            wordListScanner.next(); // now is ( or using
                            String _c = wordListScanner.current();
                            if (ParseUtil.isWord(_c, "(")) {
                                // now is (
                                indexType = null;
                                _index_expr = wordListScanner.findMatchDiffPair("(", ")");
                            } else if (ParseUtil.isWord(_c, "using")) {
                                wordListScanner.next(); // now is btree or hash
                                indexType = wordListScanner.current();
                                wordListScanner.next(); // now is (
                                _index_expr = wordListScanner.findMatchDiffPair("(", ")");
                            } else {
                                // 一种异常的情况
                                throw new RuntimeException("解析索引异常 debug:" + wordListScanner.debug());
                            }
                        }
                        // next step is index_option
                        _step = CreateDefinitionTypeEnum.index_option;
                        if (ddlIndex.isPrimary() && StringUtils.isNotBlank(indexName)) {
                            throw new RuntimeException("解析索引异常 primary key 不能有index_name ");
                        }
                        if (ddlIndex.isForeign() && StringUtils.isNotBlank(indexType)) {
                            throw new RuntimeException("解析索引异常 FOREIGN KEY 不能有index_type ");
                        }
                        if (ddlIndex.isNormal() || ddlIndex.isFullText() || ddlIndex.isSpatial()) {
                            ddlIndex.setIndexName(indexName);
                            ddlIndex.setIndexType(indexType);
                            ddlIndex.setKeyPart(_index_expr);
                            _step = CreateDefinitionTypeEnum.index_option;
                        } else if (ddlIndex.isPrimary()) {
                            ddlIndex.setIndexType(indexType);
                            ddlIndex.setKeyPart(_index_expr);
                            _step = CreateDefinitionTypeEnum.index_option;
                        } else if (ddlIndex.isUnique()) {
                            ddlIndex.setIndexName(indexName);
                            ddlIndex.setIndexType(indexType);
                            ddlIndex.setKeyPart(_index_expr);
                            _step = CreateDefinitionTypeEnum.index_option;
                        } else if (ddlIndex.isForeign()) {
                            ddlIndex.setIndexName(indexName);
                            ddlIndex.setColName(_index_expr);
                            // 后面可能有 reference_definition 要解析
                        }
                        break;
                    case "references":
                        _step = CreateDefinitionTypeEnum.reference_definition;
                        ReferenceDefinition referenceDefinition = new ReferenceDefinition();
                        String tblName = next;
                        referenceDefinition.setTblName(tblName);
                        wordListScanner.next();
                        if (ParseUtil.isWord(nextnext, "(")) {
                            wordListScanner.next(); // now is (
                            String _ref_word = wordListScanner.findMatchDiffPair("(", ")");
                            referenceDefinition.setKeyPart(_ref_word);
                            ddlIndex.setReferenceDefinition(referenceDefinition);
                        } else {
                            throw new RuntimeException("REFERENCES属性不正确 没有指定key_part " + wordListScanner.debug());
                        }
                        break;
                    case "match":
                        if (_step == CreateDefinitionTypeEnum.reference_definition) {
                            ddlIndex.getReferenceDefinition().setMatch(next);
                            wordListScanner.next();
                        }
                        break;
                    case "delete":
                        if (_step == CreateDefinitionTypeEnum.reference_definition) {
                            if (ParseUtil.isWord(pre, "ON")) {
                                // reference_option 有可能是一个 有可能是2个
                                // RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
                                String _on_delete = next;
                                if (ParseUtil.isWord(_on_delete, "SET") || ParseUtil.isWord(_on_delete, "NO")) {
                                    _on_delete = next + " " + nextnext;
                                    ddlIndex.getReferenceDefinition().setOnDelete(_on_delete);
                                    wordListScanner.next();
                                    wordListScanner.next();
                                } else {
                                    ddlIndex.getReferenceDefinition().setOnDelete(_on_delete);
                                    wordListScanner.next();
                                }
                            }
                        }
                        break;
                    case "update":
                        if (_step == CreateDefinitionTypeEnum.reference_definition ||
                                _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(pre, "ON")) {
                                // reference_option 有可能是一个 有可能是2个
                                // RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
                                String _on_update = next;
                                if (ParseUtil.isWord(_on_update, "SET") || ParseUtil.isWord(_on_update, "NO")) {
                                    _on_update = next + " " + nextnext;
                                    ddlIndex.getReferenceDefinition().setOnUpdate(_on_update);
                                    wordListScanner.next();
                                    wordListScanner.next();
                                } else {
                                    ddlIndex.getReferenceDefinition().setOnUpdate(_on_update);
                                    wordListScanner.next();
                                }
                            }
                        }
                        break;
                    case "restrict":
                        break;
                    case "cascade":
                        break;
                    case "action":
                        break;
                    case "no":
                        break;
                    case "fulltext":
                        ddlIndex.setFullText(true);
                        ddlIndex.setNormal(false);
                        ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                        break;
                    case "spatial":
                        ddlIndex.setSpatial(true);
                        ddlIndex.setNormal(false);
                        ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                        break;
                    case "constraint":
                        if(_step != CreateDefinitionTypeEnum.check_constraint_definition) {
                            ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                        }
                        break;
                    case "primary":
                        ddlIndex.setPrimary(true);
                        ddlIndex.setNormal(false);
                        ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                        break;
                    case "unique":
                        ddlIndex.setUnique(true);
                        ddlIndex.setNormal(false);
                        ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                        break;
                    case "foreign":
                        ddlIndex.setForeign(true);
                        ddlIndex.setNormal(false);
                        ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                        break;
                    case "using":
                        // now is index_type
                        _step = CreateDefinitionTypeEnum.index_type;
                        break;
                    case "btree":
                        if (_step == CreateDefinitionTypeEnum.index_type) {
                            ddlIndex.setIndexType("BTREE");
                        }
                        break;
                    case "hash":
                        if (_step == CreateDefinitionTypeEnum.index_type) {
                            ddlIndex.setIndexType("HASH");
                        }
                        break;
                    case "check":
                        // 这里要判断下接下来的是不是 check_constraint_definition
                        // check_constraint_definition 在2声明阶段都有
                        // 1 列声明阶段
                        // 2 索引声明阶段
                        // 要区分这2个阶段 这里从代码层面 保证了这里是2阶段
                        _step = CreateDefinitionTypeEnum.check_constraint_definition;
                        CheckConstraintDefinition checkConstraintDefinition =
                                new CheckConstraintDefinition();
                        ddlIndex.setCheckConstraintDefinition(checkConstraintDefinition);
                        if (ParseUtil.isWord(pre, "constraint")) {
                            checkConstraintDefinition.setConstraintSymbol(null);
                            wordListScanner.next(); // skip check now is (
                        } else {
                            checkConstraintDefinition.setConstraintSymbol(pre);
                            wordListScanner.next(); // skip symbol now is (
                        }
                        String _check_expr = wordListScanner.findMatchDiffPair("(", ")");
                        ddlIndex.getCheckConstraintDefinition().setCheckExpr(_check_expr);
                        break;
                    case "enforced":
                        if (_step == CreateDefinitionTypeEnum.check_constraint_definition) {
                            boolean _enforced = true;
                            if (ParseUtil.isWord(pre, "NOT")) {
                                _enforced = false;
                            }
                            ddlIndex.getCheckConstraintDefinition().setEnforced(_enforced);
                        }
                        break;
                    default:
                        if (_step == CreateDefinitionTypeEnum.index) {
                            if (ParseUtil.isWord(pre, "constraint")) {
                                ddlIndex.setPre(ddlIndex.getPre() + " " + current);
                            }
                        }
                        if (ParseUtil.isWord(pre, "constraint")) {
                            ddlIndex.setConstraint(wordListScanner.current());
                        }

//                        if (_step == CreateDefinitionTypeEnum.index_name) {
//                            ddlIndex.setIndexName(current);
//                            _step = CreateDefinitionTypeEnum.index_type;
//                        }
                        break;
                }
                wordListScanner.next();
            }
            res.add(ddlIndex);
        }

        return res;
    }

    private Integer getColumnLen(WordListScanner wordListScanner) {

        String next = wordListScanner.getNextWord();
        String nextnext = wordListScanner.getNextNextWord();
        if (StringUtils.equalsIgnoreCase(next, "(") && StringUtils.isNumeric(nextnext)) {
            return Integer.parseInt(nextnext);
        }
        return null;
    }
}
